package ch.fhnw.qualiscan.application.models;

import java.util.List;

import ch.fhnw.qualiscan.Config;

import ch.fhnw.qualiscan.core.Model;
import ch.fhnw.qualiscan.core.db.pojos.Answer;
import ch.fhnw.qualiscan.core.db.pojos.BestPractice;
import ch.fhnw.qualiscan.core.db.pojos.Confidence;
import ch.fhnw.qualiscan.core.db.pojos.CoordinatorRelevance;
import ch.fhnw.qualiscan.core.db.pojos.Domain;
import ch.fhnw.qualiscan.core.db.pojos.DomainDescription;
import ch.fhnw.qualiscan.core.db.pojos.DomainText;
import ch.fhnw.qualiscan.core.db.pojos.FinalEvaluation;
import ch.fhnw.qualiscan.core.db.pojos.Language;
import ch.fhnw.qualiscan.core.db.pojos.Question;
import ch.fhnw.qualiscan.core.db.pojos.QuestionText;
import ch.fhnw.qualiscan.core.db.pojos.Role;
import ch.fhnw.qualiscan.core.db.pojos.RoleText;
import ch.fhnw.qualiscan.core.db.pojos.Survey;
import ch.fhnw.qualiscan.core.db.pojos.SurveyUserRole;
import ch.fhnw.qualiscan.core.db.pojos.University;
import ch.fhnw.qualiscan.core.db.pojos.User;
import ch.fhnw.qualiscan.core.db.pojos.Permission;
import ch.fhnw.qualiscan.core.db.pojos.Questionnaire;

public class AdminModel extends Model{
	
	/**
	 * Gets a list of all domains of a given questionnaire.
	 * @return list containing Domain objects.
	 */
        public List<Domain> getDomains(Questionnaire currentQuestionnaire) {
            @SuppressWarnings("unchecked")
            List<Domain> domains = hibernateSession.getSession().createQuery("from Domain as domain where questionnaireId = :id")
                    .setParameter("id", currentQuestionnaire.getId())
                    .list();
            return domains;
        }

        
	/**
	 * Gets the DomainText for a specified domain and language.
	 * @param domain the domain
	 * @param language the language
	 * @return DomainText object
	 */
	public DomainText getDomainText(Domain domain, Language language) {
		DomainText dtxt = (DomainText) hibernateSession.getSession().createQuery("from DomainText as dt where domain = :domain and language = :language")
		.setParameter("domain", domain)
		.setParameter("language", language)
		.uniqueResult();
		
		if (dtxt == null) {
			dtxt = new DomainText();
			dtxt.setText("");
		}
		
		return dtxt;
	}
	
	/**
	 * Gets the DomainDescription for a specified domain and language.
	 * @param domain the domain
	 * @param language the language
	 * @return DomainText object
	 */
	public DomainDescription getDomainDescription(Domain domain, Language language) {
		DomainDescription dtxt = (DomainDescription) hibernateSession.getSession().createQuery("from DomainDescription as dt where domain = :domain and language = :language")
		.setParameter("domain", domain)
		.setParameter("language", language)
		.uniqueResult();
		
		if (dtxt == null) {
			dtxt = new DomainDescription();
			dtxt.setText("");
		}
		
		return dtxt;
	}
	
	/**
	 * Checks if there's a DomainText for a specified Domain and Language
	 * @param domain the domain
	 * @param language the language
	 * @return true or false.
	 */
	public boolean existsDomainText(Domain domain, Language language) {
		DomainText dtxt = (DomainText) hibernateSession.getSession().createQuery("from DomainText as dt where domain = :domain and language = :language")
		.setParameter("domain", domain)
		.setParameter("language", language)
		.uniqueResult();
		
		if (dtxt != null) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Gets a list of all languages.
	 * @return List containing Language objects.
	 */
	public List<Language> getLanguages() {
		List<Language> languageList = hibernateSession.getSession().createQuery("from Language").list();
		
		return languageList;
	}
	
	/**
	 * Deletes a domain from the database
	 * @param domain the domain to be deleted
	 */
	public void deleteDomain(Domain domain) {
		hibernateSession.closeSession();
		Domain d = (Domain) hibernateSession.getSession().get(Domain.class, domain.getId());
		hibernateSession.getSession().delete(d);
		hibernateSession.closeSession();
	}
	
	/**
	 * Gets the QuestionText for a specified question and language
	 * @param question the question
	 * @param language the language
	 * @return QuestionText object
	 */
	public QuestionText getQuestionText(Question question, Language language) {
		QuestionText qtxt = (QuestionText) hibernateSession.getSession().createQuery("from QuestionText as dt where question = :question and language = :language")
		.setParameter("question", question)
		.setParameter("language", language)
		.uniqueResult();
		
		if (qtxt == null) {
			qtxt = new QuestionText();
			qtxt.setText("");
		}

		
		return qtxt;
	}
	
	/**
	 * Checks if there is a QuestionText for a specified Question and Language
	 * @param question the question
	 * @param language the language
	 * @return true or false.
	 */
	public boolean existsQuestionText(Question question, Language language) {
		QuestionText qtxt = (QuestionText) hibernateSession.getSession().createQuery("from QuestionText as dt where question = :question and language = :language")
		.setParameter("question", question)
		.setParameter("language", language)
		.uniqueResult();
		
		if (qtxt != null) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Deletes a question from the db.
	 * @param question the question to be deleted
	 * @param subquestion true if the question is a subquestion
	 * @param domain the domain the question belongs to
	 */
	public void deleteQuestion(Question question, boolean subquestion, Domain domain) {
		//Delete from Domain
		if (subquestion == false) {
			domain.removeQuestion(question);
			hibernateSession.getSession().merge(domain);
		}
		
		//Delete from Question
		if (subquestion == true) {
			Question tq = (Question) hibernateSession.getSession().get(Question.class, question.getParentQuestion().getId());
			tq.removeSubquestion(question);
			hibernateSession.getSession().merge(tq);
		}

		hibernateSession.closeSession();
		Question q = (Question) hibernateSession.getSession().get(Question.class, question.getId());
		hibernateSession.getSession().delete(q);
		hibernateSession.closeSession();
	}
	
	/**
	 * Deletes a user from the db.
	 * @param user the user to be deleted.
	 */
	public void deleteUser(User user) {
		//Answers
		
		List<Answer> answerList = hibernateSession.getSession().createQuery("from Answer where user = :user")
		.setParameter("user", user)
		.list();
		
		for (int a = 0; a < answerList.size(); a++ ) {
			Question q = (Question) hibernateSession.getSession().get(Question.class, answerList.get(a).getQuestion().getId());
			q.removeAnswer(answerList.get(a));
			hibernateSession.getSession().merge(q);
			hibernateSession.getSession().delete(answerList.get(a));
		}
		
		//Best Practices
		List<BestPractice> bpList = hibernateSession.getSession().createQuery("from BestPractice where user = :user")
		.setParameter("user", user)
		.list();
		
		for (int b = 0; b < bpList.size(); b++) {
			Domain d = (Domain) hibernateSession.getSession().get(Domain.class, bpList.get(b).getDomain().getId());
			d.removeBestpractice(bpList.get(b));
			hibernateSession.getSession().merge(d);
			hibernateSession.getSession().delete(bpList.get(b));
		}
		
		//Confidence
		List<Confidence> confidenceList = hibernateSession.getSession().createQuery("from Confidence where user = :user")
		.setParameter("user", user)
		.list();
		
		for (int c = 0; c < confidenceList.size(); c++) {
			Domain d = (Domain) hibernateSession.getSession().get(Domain.class, confidenceList.get(c).getDomain().getId());
			d.removeConfidence(confidenceList.get(c));
			hibernateSession.getSession().merge(d);
			hibernateSession.getSession().delete(confidenceList.get(c));
		}
		
		//Final Evaluation
		List<FinalEvaluation> evaluationList = hibernateSession.getSession().createQuery("from FinalEvaluation where user = :user")
		.setParameter("user", user)
		.list();
		
		for (int e = 0; e < evaluationList.size(); e++) {
			hibernateSession.getSession().delete(evaluationList.get(e));
		}
		
		//Surveys
		List<SurveyUserRole> surList = hibernateSession.getSession().createQuery("from SurveyUserRole where user = :user")
		.setParameter("user", user)
		.list();
		
		for(int s = 0; s < surList.size(); s++) {
			if (surList.get(s).getRole().getId() == Config.COORDINATOR_ID) {
				deleteSurvey(surList.get(s).getSurvey());
			}
			else {
				hibernateSession.getSession().delete(surList.get(s));
			}
		}
		//User
		hibernateSession.closeSession();
		User u = (User) hibernateSession.getSession().get(User.class, user.getId());
		hibernateSession.getSession().delete(u);
		hibernateSession.closeSession();
		hibernateSession.getSession();
	}
	
	/**
	 * Deletes a survey from the db.
	 * @param survey the survey to be deleted.
	 */
	public void deleteSurvey(Survey survey) {
		//Answers
		List<Answer> answerList = hibernateSession.getSession().createQuery("from Answer where survey = :survey")
		.setParameter("survey", survey)
		.list();
		
		for (int a = 0; a < answerList.size(); a++ ) {
			Question q = (Question) hibernateSession.getSession().get(Question.class, answerList.get(a).getQuestion().getId());
			q.removeAnswer(answerList.get(a));
			hibernateSession.getSession().merge(q);
			hibernateSession.getSession().delete(answerList.get(a));
		}
		
		//BestPractice
		List<BestPractice> bpList = hibernateSession.getSession().createQuery("from BestPractice where survey = :survey")
		.setParameter("survey", survey)
		.list();
		
		for (int b = 0; b < bpList.size(); b++) {
			Domain d = (Domain) hibernateSession.getSession().get(Domain.class, bpList.get(b).getDomain().getId());
			d.removeBestpractice(bpList.get(b));
			hibernateSession.getSession().merge(d);
			hibernateSession.getSession().delete(bpList.get(b));
		}
		//Confidence
		List<Confidence> confidenceList = hibernateSession.getSession().createQuery("from Confidence where survey = :survey")
		.setParameter("survey", survey)
		.list();
		
		for (int c = 0; c < confidenceList.size(); c++) {
			Domain d = (Domain) hibernateSession.getSession().get(Domain.class, confidenceList.get(c).getDomain().getId());
			d.removeConfidence(confidenceList.get(c));
			hibernateSession.getSession().merge(d);
			hibernateSession.getSession().delete(confidenceList.get(c));
		}
		
		
		//Final Evaluation
		List<FinalEvaluation> evaluationList = hibernateSession.getSession().createQuery("from FinalEvaluation where survey = :survey")
		.setParameter("survey", survey)
		.list();
		
		for (int e = 0; e < evaluationList.size(); e++) {
			hibernateSession.getSession().delete(evaluationList.get(e));
		}
		
		//Relevance
		List<CoordinatorRelevance> relList = hibernateSession.getSession().createQuery("from CoordinatorRelevance where survey = :survey")
		.setParameter("survey", survey)
		.list();
		
		for (int cr = 0; cr < relList.size(); cr++) {
			hibernateSession.getSession().delete(relList.get(cr));
		}
		
		
		//SurveyUserRole
		List<SurveyUserRole> surList = hibernateSession.getSession().createQuery("from SurveyUserRole where survey = :survey")
		.setParameter("survey", survey)
		.list();
		
		for (int su = 0; su < surList.size(); su++) {
			hibernateSession.getSession().delete(surList.get(su));
		}
		
		hibernateSession.closeSession();
		Survey s = (Survey) hibernateSession.getSession().get(Survey.class, survey.getId());
		hibernateSession.getSession().delete(s);
		hibernateSession.closeSession();
	}
	
	/**
	 * Returns all surveys in the table
	 * @return returns a list of surveys.
	 */
	public List<Survey> getSurveys() {
		List<Survey> surveyList = hibernateSession.getSession().createQuery("from Survey")
		.list();
		
		return surveyList;
	}

	public void deleteUnusedUser(User oldUser) {
		hibernateSession.getSession().delete(oldUser);
	}
	
	/**
	 * Gets all universities from the db
	 * @return list containing university pojos
	 */
	public List<University> getUniversities() {
		List<University> universityList = hibernateSession.getSession().createQuery("from University")
		.list();
		
		return universityList;
	}
	
	/**
	 * Updates a university
	 * @param title the new title
	 * @param university the university to be updated
	 */
	public void updateUniversity(String title, University university) {
		university.setTitle(title);
		hibernateSession.getSession().update(university);
		hibernateSession.closeSession();
	}
	
	/**
	 * Saves a new university to the db
	 * @param title the title of the university
	 */
	public void saveUniversity(String title) {
		University university = new University();
		university.setTitle(title);
		
		hibernateSession.getSession().save(university);
		hibernateSession.closeSession();
		
	}

	public List<Role> getRoles() {
		List<Role> roleList = hibernateSession.getSession().createQuery("from Role")
		.list();
		
		return roleList;
	}
	
	public RoleText getRoleText(Role role, Language language) {
		RoleText rtxt = (RoleText) hibernateSession.getSession().createQuery("from RoleText as dt where role = :role and language = :language")
		.setParameter("role", role)
		.setParameter("language", language)
		.uniqueResult();
		
		if (rtxt == null) {
			rtxt = new RoleText();
			rtxt.setTitle("");
		}
		
		return rtxt;
	}
	
	

	public List<Permission> getPermissions() {
		List<Permission> permissionList = hibernateSession.getSession().createQuery("from Permission")
		.list();
		
		return permissionList;
	}
	
	public boolean existsRoleText(Role role, Language language) {
		RoleText rtxt = (RoleText) hibernateSession.getSession().createQuery("from RoleText as rt where role = :role and language = :language")
		.setParameter("role", role)
		.setParameter("language", language)
		.uniqueResult();
		
		if (rtxt != null) {
			return true;
		}
		
		return false;
	}
}
